package util

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"strings"
	"time"
)

func T_clock1_single_routine()  {
	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	} else {
		log.Println("listening on localhost:8000")
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err)
			continue
		}
		handleConn(conn)
	}
}

func handleConn(c net.Conn)  {
	defer c.Close()
	i := 0
	for {
		_, err := io.WriteString(c, time.Now().Format("15.04:05\n"))
		if err != nil {
			return // e.g., client disconnected
		}
		i++
		if i == 5 {  // 这是我自己加的，看看服务端停写后，client会怎么样
			break
		}
		time.Sleep(1 * time.Second)
	}
}

func T_clock2_multiple_routine()  {
	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	} else {
		log.Println("listening on localhost:8000")
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err)
			continue
		}
		log.Println("client ", conn, " accepted")
		go handleConn(conn)
	}
}

func mustCopy(dst io.Writer, src io.Reader)  {
	// io.Copy为何看起来像是循环在读似的？不是读一次就返回吗？
	// 调查发现，io.Reader的Read内部实现其实是在loop中，每次读一chunk的数据，直至io.EOF
	if n , err := io.Copy(dst, src); err != nil {
		log.Fatal(err)
	} else {
		log.Println("Read n: ", n, " err: ", err)
	}
}

// 8.2
func T_netcat1() {
	conn, err := net.Dial("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	log.Println("begin to copy data from connection to stdout")
	mustCopy(os.Stdout, conn)
	log.Println("end")
}

// 8.3, 这是用于配合echo server的，不是time server
func T_netcat2()  {
	conn, err := net.Dial("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
	go mustCopy(os.Stdout, conn)
	mustCopy(conn, os.Stdin) // 如果main goroutine退出，那么background routine也被迫退出
}

func T_echo_server() {
	echo := func(c net.Conn, shout string, delay time.Duration) {
		fmt.Fprintln(c, "\t", strings.ToUpper(shout))
		time.Sleep(delay)
		fmt.Fprintln(c, "\t", shout)
		time.Sleep(delay)
		fmt.Fprintln(c, "\t", strings.ToLower(shout))
	}

	handleEchoConn := func(c net.Conn) {
		input := bufio.NewScanner(c)
		for input.Scan() {
			go echo(c, input.Text(), 1 * time.Second)
		}
		c.Close()
	}

	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	} else {
		log.Println("listening on localhost:8000")
	}

	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err)
			continue
		}
		log.Println("client ", conn, " accepted")
		go handleEchoConn(conn)
	}
}